#include "CtrlScreen.h"
#include "CMediaFile.h"
#include "CtrlRadarChart.h"
#include "GenOpt.h"
#include "qevent.h"
#include <QDir>
#include <QList>
#include <QStyle>
#include <qcontainerfwd.h>

CtrlScreen::CtrlScreen(QWidget *parent) : QWidget(parent) {
  avm_ = nullptr;
  ui.setupUi(this);
  pause_ = false;
  seeking_ = false;
  render_ = nullptr;
  continue_to_crop_ = false;
  crop_start_ = 0;
  crop_stop_ = 0;
  interval_ = 1;
  crop_type_ = 0;
  media_info_ = {0};
  render_frame_ = {0};
  radar_chart_ = nullptr;
  radar_data_size_ = 0;
  Init();
}

CtrlScreen::~CtrlScreen() {
  avm_->Close();
  render_->DestroyWnd();
  if (avm_) {
    delete avm_;
    avm_ = nullptr;
  }
  if (render_) {
    delete render_;
    render_ = nullptr;
  }
}

void CtrlScreen::Init() {
  setMouseTracking(true);
  ui.labelScreen->setAttribute(Qt::WA_TranslucentBackground);
  ui.labelScreen->setMouseTracking(true);
  ui.sliderProcess->setTracking(true);

  avm_ = new CMediaFile();
  if (!avm_) {
    // QLOG_FATAL() << "avm initialize failed";
  }
  avm_->SetFrameValidCallBackFunc(CtrlScreen::FrameValid, this);

  render_ = new CVRender();
  if (!render_) {
    // QLOG_FATAL() << "render initialize failed";
  }
  render_->CreateWnd((HWND)ui.labelScreen->winId());

  OnSize();
  connect(ui.sliderProcess, SIGNAL(sliderPressed()), this,
          SLOT(OnSliderPressed()));
  connect(ui.sliderProcess, SIGNAL(sliderMoved(int)), this,
          SLOT(OnSliderChanged(int)));
  connect(ui.lineEditFrame, SIGNAL(textChanged(const QString &)), this,
          SLOT(OnTextProcessChanged(const QString &)));
  QObject::connect(this, &CtrlScreen::sigUpdateScreen, this,
                   &CtrlScreen::OnUpdateScreen);
  connect(ui.radarChart, SIGNAL(SPointClicked(const QPointF &)), this,
          SLOT(OnPointClickedSlot(const QPointF &)));
  ui.sliderProcess->installEventFilter(this);

  radar_chart_ = new QChart();
  ui.radarChart->setChart(radar_chart_);
}

int CtrlScreen::OnSliderPressed() {
  Play(false);
  seeking_ = true;
  return 0;
}

int CtrlScreen::OnSliderReleased() {
  int index = ui.sliderProcess->value();
  avm_->SeekByFrame(index);
  seeking_ = false;
  return 0;
}

int CtrlScreen::OnSliderChanged(int val) {
  UpdateSliderProcess(val);
  OnUpdateRadarIndex(val);
  return 0;
}

void CtrlScreen::OnTextProcessChanged(const QString &text) {
  int val = 0;
  if (pause_ && (!seeking_)) {
    if (text.isEmpty()) {
      val = 0;
    } else {
      val = text.toInt();
    }

    if (val >= media_info_.total_frames) {
      val = media_info_.total_frames - 1;
    }
    avm_->SeekByFrame(val);
    UpdateSliderProcess(val);
    OnUpdateRadarIndex(val);
  }
}

int CtrlScreen::OpenMediaFile(QString file) {
  if (file == cur_file_) {
    return 0;
  }
  cur_file_ = file;
  char *ch;
  QByteArray ba = file.toUtf8();
  ch = ba.data();
  if (avm_->GetState() > CMediaFile::AVM_STATE_CLOSE) {
    avm_->Close();
  }
  int ret = avm_->Open(ch, 0);
  if (ret != 0) {
    return -1;
  }
  avm_->GetInfo(&media_info_);
  for (int i = 0; i < 3; i++) {
    if (render_frame_.data[i]) {
      delete[] render_frame_.data[i];
    }
    render_frame_.data[i] = new uint8_t[media_info_.width * media_info_.height];
  }
  UpdateSliderProcess(0);
  UpdateSliderMaxProcess(media_info_.total_frames - 1);
  render_->SetDisplayMode(DisMode_FitWindow_KeepRatio, nullptr,
                          media_info_.width, media_info_.height);
  OnSize();
  Play(true);

  OnShowRadarChart(file);
  OnUpdateRadarIndex(0);
  return 0;
}

int CtrlScreen::OnShowRadarChart(QString video_files) {
  QString file_radar = CGenOpt::GetRadarFileName(video_files);
  SEI_MAP raw_data;

  CMediaFile::ReadRadarDataFromFile(file_radar.toUtf8().constData(), raw_data);
  auto it = raw_data.begin();
  radar_data_size_ = 0;
  chart_data_.clear();
  for (; it != raw_data.end(); it++) {
    uint8_t *raw_array = (uint8_t *)it->second.data();
    uint32_t dist = (int)raw_array[4] << 8 | raw_array[3];
    chart_data_.append(dist);
  }
  radar_data_size_ = chart_data_.size();
  ui.radarChart->UpdateRadarData(chart_data_);
  return 0;
}

int CtrlScreen::UpdateSliderProcess(int cur) {
  ui.sliderProcess->setValue(cur);
  ui.labelFrame->setText(
      QString("%1/%2").arg(cur).arg(media_info_.total_frames));
  return 0;
}

int CtrlScreen::UpdateSliderMaxProcess(int max) {
  ui.sliderProcess->setRange(0, max);
  ui.sliderProcess->setSingleStep(1);
  ui.sliderProcess->setTracking(false);
  ui.labelFrame->setText(QString("0/%2").arg(max));
  return 0;
}

void CtrlScreen::Play(bool play) {
  int ret;
  if (play) {
    ret = avm_->Play();
    pause_ = false;
  } else {
    ret = avm_->Pause();
    pause_ = true;
  }

  ui.pbPlay->setText(pause_ ? "播放" : "暂停");
  ui.lineEditFrame->setEnabled(pause_);
}

void CtrlScreen::OnUpdateScreen() {
  render_->Update(render_frame_.data, render_frame_.size, render_frame_.width,
                  render_frame_.height, render_frame_.stride,
                  RenderFormat_YUV420P);
  if (render_frame_.state != CMediaFile::AVM_STATE_PAUSE) {
    UpdateSliderProcess(render_frame_.index);
    OnUpdateRadarIndex(render_frame_.index);
  }
}

void CtrlScreen::OnUpdateRadarIndex(uint64_t index) {
  if (chart_data_.isEmpty()) {
    return;
  }
  uint64_t radar_index = GetRadarPointByFrameIndex(index);
  QString strRadarPos =
      QString("%1: %2").arg(radar_index).arg(chart_data_[radar_index]);
  ui.labelRadar->setText(strRadarPos);
}

void CtrlScreen::FrameValid(AVMFrame_t *pFrame, void *userdata) {
  CtrlScreen *p = (CtrlScreen *)userdata;
  for (int i = 0; i < 3; i++) {
    memcpy(p->render_frame_.data[i], pFrame->data[i], pFrame->data_bytes[i]);
    p->render_frame_.stride[i] = pFrame->stride[i];
    p->render_frame_.data_bytes[i] = pFrame->data_bytes[i];
  }
  p->render_frame_.height = pFrame->height;
  p->render_frame_.width = pFrame->width;
  p->render_frame_.index = pFrame->index;
  p->render_frame_.pts = pFrame->pts;
  p->render_frame_.size = pFrame->size;
  p->render_frame_.state = pFrame->state;
  emit p->sigUpdateScreen();
}

void CtrlScreen::on_pbPlay_clicked() {
  int ret = 0;
  Play(pause_);
  return;
}

void CtrlScreen::resizeEvent(QResizeEvent *event) {
  QWidget::resizeEvent(event);
}

void CtrlScreen::moveEvent(QMoveEvent *event) { QWidget::moveEvent(event); }

void CtrlScreen::on_pbBackward_clicked() {
  int value = ui.sliderProcess->value();
  value -= 30;
  if (value < ui.sliderProcess->minimum()) {
    value = ui.sliderProcess->minimum();
  }
}

void CtrlScreen::on_pbForward_clicked() {
  int value = ui.sliderProcess->value();
  value += 30;
  if (value > ui.sliderProcess->maximum()) {
    value = ui.sliderProcess->maximum();
  }
}

int CtrlScreen::OnSize() {
  QRect rc = ui.labelScreen->geometry();
  QPoint pt;
  pt = ui.labelScreen->mapToGlobal(QPoint(0, 0));
  RenderRect_t disp_rc = {0};
  render_->GetDisplayRect(&disp_rc);
  pt = ui.labelScreen->mapToGlobal(QPoint(disp_rc.x, disp_rc.y));
  return 0;
}

bool CtrlScreen::eventFilter(QObject *obj, QEvent *event) {
  if (obj == ui.sliderProcess) {
    if (event->type() == QEvent::MouseButtonRelease) {
      QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
      if (mouseEvent->button() == Qt::LeftButton) {
        int value = QStyle::sliderValueFromPosition(
            ui.sliderProcess->minimum(), ui.sliderProcess->maximum(),
            mouseEvent->pos().x(), ui.sliderProcess->width());
        ui.sliderProcess->setValue(value);
        OnSliderReleased();
      }
    }
  }
  return QObject::eventFilter(obj, event);
}

uint32_t CtrlScreen::GetRadarPointByFrameIndex(uint64_t index) {
  uint32_t radar_index = 0;
  uint64_t total_frame = media_info_.total_frames;
  radar_index = (uint32_t)((double)radar_data_size_ * (double)index /
                           (double)total_frame);
  return radar_index;
}

uint64_t CtrlScreen::GetFrameIndexFromRadarPoint(const QPointF &point) {
  uint64_t frame_index = 0;
  uint64_t total_frame = media_info_.total_frames;
  const uint32_t offset_frame = 15;
  total_frame -= offset_frame;
  frame_index =
      (uint64_t)((double)total_frame * point.x() / (double)radar_data_size_);
  return frame_index;
}

void CtrlScreen::OnPointClickedSlot(const QPointF &point) {
  uint64_t frame_index;
  Play(false);
  seeking_ = true;
  QString strRadarPos = QString("%1: %2")
                            .arg((uint32_t)point.x())
                            .arg(chart_data_[(uint32_t)point.x()]);
  ui.labelRadar->setText(strRadarPos);
  frame_index = GetFrameIndexFromRadarPoint(point);
  avm_->SeekByFrame(frame_index);
  seeking_ = false;
}
